<?php

namespace Biz\tools;

use Doraemon\pockets\constInterface\AppType;
use Doraemon\service\Location\Search;
use Doraemon\service\position\PositionApi;
use Doraemon\service\UserPortrait\UserPortraitApi;
use Doraemon\tools\HhzClient;
use Doraemon\tools\HhzEnv;
use Doraemon\tools\Log;
use Hhz\AdministrativeRegion\Region;


class  Location
{
    public const SHOW_CITIES = ['110100'];//能显示门店信息的城市id(目前只有北京)
    public const DEFAULT_CITY_CODE = '110100';//默认城市id
    public const FIRST_CITIES = [
        '110000',
        '500000',
        '310000',
        '120000',
        '810000',
        '820000'
    ];//一级城市id（1：北京 2：天津 9：上海 22：重庆 32：香港 33：澳门）
    public const SHOW_UIDS = ['464154', '1090425'];//设计师白名单

    private int $uid;//查询用户uid
    private $latitude = '';//纬度
    private $longitude = '';//经度
    private $areaCode = '';//区域编码
    private $areaName = '';//区域名称

    private array $location = [];//经纬度longitude,latitude
    private array $cityInfo = [];//城市信息area_code,area_name
    private array $locationInfo = [];//位置详细信息（包含经纬度及城市信息）

    /**
     * @param $uid
     * @param string $longitude
     * @param string $latitude
     * @throws \Exception
     */
    public function __construct($uid, $longitude = '', $latitude = '')
    {
        return [];//门店业务下线
        $this->uid = $uid;
        if (!empty($uid) || ($longitude && $latitude)) {
            $this->locationInfo = $this->_getUserLocationInfo($uid, $longitude, $latitude);
            if ($this->locationInfo) {
                $this->latitude = $this->locationInfo['latitude'];
                $this->longitude = $this->locationInfo['longitude'];
                $this->areaCode = $this->locationInfo['area_code'];
                $this->areaName = $this->locationInfo['area_name'];
                $this->location = [
                    'latitude' => $this->locationInfo['latitude'],
                    'longitude' => $this->locationInfo['longitude'],
                ];
                $this->cityInfo = [
                    'city_id' => $this->locationInfo['city_id'],
                    'city_name' => $this->locationInfo['city_name'],
                    'area_name' => $this->locationInfo['area_name'],
                    'area_code' => $this->locationInfo['area_code'],
                ];
            }
        }
    }

    /**
     * 获取纬度
     *
     * @return mixed|string
     */
    public function getLatitude()
    {
        return $this->latitude;
    }

    /**
     * 获取经度
     *
     * @return mixed|string
     */
    public function getLongitude()
    {
        return $this->longitude;
    }

    /**
     * 获取城市id
     *
     * @return int|mixed
     */
    public function getAreaCode()
    {
        $appType = HhzClient::getClientType();
        if ((empty($this->areaCode) && $appType == AppType::APPTYPE_STORE_MINIPROGRAM) || in_array($this->uid,
                self::SHOW_UIDS, false)) {
            $this->areaCode = self::DEFAULT_CITY_CODE;//小程序默认北京
        }
        return $this->areaCode;
    }

    /**
     * 获取城市名称
     *
     * @return mixed|string
     */
    public function getCityName()
    {
        $appType = HhzClient::getClientType();
        if (empty($this->areaName) && $appType == AppType::APPTYPE_STORE_MINIPROGRAM) {
            $this->areaName = '北京';//小程序默认北京
        }
        return $this->areaName;
    }

    /**
     * 获取位置详细信息
     *
     * @return array
     */
    public function getLocationInfo()
    {
        return $this->locationInfo;
    }

    /**
     * 获取城市信息
     *
     * @return array
     */
    public function getCityInfo()
    {
        $appType = HhzClient::getClientType();
        if (empty($this->cityInfo) && $appType == AppType::APPTYPE_STORE_MINIPROGRAM) {
            //小程序默认北京
            $this->cityInfo = [
                'area_name' => '北京',
                'area_code' => '110100',
            ];
            $this->areaCode = self::DEFAULT_CITY_CODE;
            $this->areaName = '北京';
        }
        return $this->cityInfo;
    }

    /**
     * 获取经纬度信息
     *
     * @return array
     */
    public function getLocation()
    {
        return $this->location;
    }

    /**
     * 是否展示门店
     *
     * @return bool
     */
    public function isShowStore()
    {
        return false;//门店业务下线
        //是否qa环境
        if (!HhzEnv::isGray() && !HhzEnv::isProduction()) {
            return true;
        }
        //是否qa环境
        $this->areaCode = $this->getAreaCode();

        if ($this->areaCode && (in_array($this->areaCode, self::SHOW_CITIES, false) || in_array($this->uid,
                    self::SHOW_UIDS,
                    false))) {
            $appType = HhzClient::getClientType();
            if (in_array($appType, [AppType::APPTYPE_IOS, AppType::APPTYPE_ANDROID], false)) {
                return true;
            }

            if ($appType == AppType::APPTYPE_STORE_MINIPROGRAM) {
                //门店小程序
                return true;
            }
        }
        return false;
    }

    /**
     * 获取用户的地理位置信息
     *
     * @param $uid
     * @param string $longitude
     * @param string $latitude
     * @return array
     * @throws \Exception
     */
    private function _getUserLocationInfo($uid, $longitude = '', $latitude = '')
    {
        if (empty($longitude) && empty($latitude)) {
            //通过用户分群查询位置信息
            $locationInfo = [];
            $userProfile = UserPortraitApi::requestFromBrand($uid, ['uid', 'city_name', 'city_id', 'longitude', 'latitude']);
            if ($userProfile && is_array($userProfile)) {
                $locationInfo['city_id'] = $userProfile['city_id'];
                $locationInfo['city_name'] = $userProfile['city_name'];
                $locationInfo['latitude'] = $userProfile['latitude'];
                $locationInfo['longitude'] = $userProfile['longitude'];
                //todo 兼容一下用户分群没有的字段
                $locationInfo['area_code'] = $userProfile['area_code'] ?: Region::getCodeByOldCode($locationInfo['city_id']);
                $locationInfo['area_name'] = $userProfile['area_name'] ?: Region::getNameByCode($locationInfo['area_code']);
            }
            return $locationInfo;
        }

        //坐标转城市
        $locationInfo['latitude'] = $latitude;
        $locationInfo['longitude'] = $longitude;
        $areaCityInfo = self::getCityInfoByLocation($latitude, $longitude);
        if (!empty($areaCityInfo)) {
            $locationInfo['city_id'] = $areaCityInfo['city_id'];
            $locationInfo['city_name'] = $areaCityInfo['city_name'];
            $locationInfo['area_code'] = $areaCityInfo['area_code'];
            $locationInfo['area_name'] = $areaCityInfo['area_name'];
        }
        return $locationInfo;
    }

    /**
     * 批量查询用户是否展示门店
     *
     * @param $uids
     * @return array
     */
    public static function isShowStoreByUids($uids)
    {
        $result = [];
        $locationInfos = self::getLocationByUids($uids);
        foreach ($uids as $uid) {
            if (isset($locationInfos[$uid])) {
                $result[$uid] = (bool)$locationInfos[$uid]['is_show_store'];
            } else {
                $result[$uid] = true;
            }
        }
        return $result;
    }

    /**
     * 批量获取用户的位置信息
     *
     * @param $uids
     * @return array
     * @throws \Exception
     */
    public static function getLocationByUids($uids)
    {
        return [];//门店业务下线
        $location = [];
        $userProfile = PositionApi::getMultiUserProfile($uids, ['longitude', 'latitude']);
        if ($userProfile && is_array($userProfile)) {
            foreach ($userProfile as $uid => $val) {
                $location[$uid]['city_id'] = $val['city_id'];
                $location[$uid]['city_name'] = $val['city_name'];
                //todo 兼容一下 用户画像没有的字段
                $location[$uid]['area_code'] = $val['area_code'] ?: Region::getCodeByOldCode($val['city_id']);
                $location[$uid]['area_name'] = $val['area_name'] ?: Region::getAreaDetailByCode($location[$uid]['area_code']);

                $location[$uid]['latitude'] = $val['latitude'];
                $location[$uid]['longitude'] = $val['longitude'];
                $location[$uid]['is_show_store'] = in_array($location[$uid]['area_code'], self::SHOW_CITIES,
                    false) ? 1 : 0;
            }
        }
        return $location;
    }

    /**
     * 计算两点地理坐标之间的距离
     *
     * @param float $longitude1 起点经度
     * @param float $latitude1 起点纬度
     * @param float $longitude2 终点经度
     * @param float $latitude2 终点纬度
     * @param Int $unit 单位 1:米 2:公里
     * @param Int $decimal 精度 保留小数位数
     * @return float
     */
    public static function getDistance($longitude1, $latitude1, $longitude2, $latitude2, $unit = 2, $decimal = 2)
    {

        $EARTH_RADIUS = 6370.996; // 地球半径系数
        $PI = pi();

        $radLat1 = $latitude1 * $PI / 180.0;
        $radLat2 = $latitude2 * $PI / 180.0;

        $radLng1 = $longitude1 * $PI / 180.0;
        $radLng2 = $longitude2 * $PI / 180.0;

        $a = $radLat1 - $radLat2;
        $b = $radLng1 - $radLng2;

        $distance = 2 * asin(sqrt(pow(sin($a / 2), 2) + cos($radLat1) * cos($radLat2) * pow(sin($b / 2), 2)));
        $distance = $distance * $EARTH_RADIUS * 1000;

        if ($unit == 2) {
            $distance = $distance / 1000;
        }

        return round($distance, $decimal);
    }

    /**
     * @param float $lng 经度
     * @param float $lat 纬度
     * @param float $distance 该点所在圆的半径，该圆与此正方形内切，默认值为1千米
     * @param int $radius 地球半径 平均6371km
     * @return array[] 正方形的四个点的经纬度坐标
     */
    public static function returnSquarePoint($lng, $lat, $distance = 1, $radius = 6371)
    {
        $dlng = 2 * asin(sin($distance / (2 * $radius)) / cos(deg2rad($lat)));
        $dlng = rad2deg($dlng);

        $dlat = $distance / $radius;
        $dlat = rad2deg($dlat);

        return [
            'left-top' => [
                'lat' => $lat + $dlat,
                'lng' => $lng - $dlng
            ],
            'right-top' => [
                'lat' => $lat + $dlat,
                'lng' => $lng + $dlng
            ],
            'left-bottom' => [
                'lat' => $lat - $dlat,
                'lng' => $lng - $dlng
            ],
            'right-bottom' => [
                'lat' => $lat - $dlat,
                'lng' => $lng + $dlng
            ],
            'max_lat' => $lat + $dlat,
            'min_lat' => $lat - $dlat,
            'max_lng' => $lng + $dlng,
            'min_lng' => $lng - $dlng,
        ];
    }

    /**
     * 百度坐标系（BD-09）转火星坐标系（GCJ-02）
     *
     * @param double $lng 百度经度
     * @param double $lat 百度纬度
     * @return array
     */
    public static function Bd09ToGcj02($lng, $lat)
    {
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $lng - 0.0065;
        $y = $lat - 0.006;
        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
        $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
        $lng = $z * cos($theta);
        $lat = $z * sin($theta);
        return ['lng' => $lng, 'lat' => $lat];
    }

    /**
     * GCJ-02(火星，高德) 坐标转换成 BD-09(百度) 坐标
     *
     * @param $lng 火星经度
     * @param $lat 火星纬度
     * @return array
     */
    public static function Gcj02ToBd09($lng, $lat)
    {
        $x_pi = 3.14159265358979324 * 3000.0 / 180.0;
        $x = $lng;
        $y = $lat;
        $z = sqrt($x * $x + $y * $y) - 0.00002 * sin($y * $x_pi);
        $theta = atan2($y, $x) - 0.000003 * cos($x * $x_pi);
        $lng = $z * cos($theta) + 0.0065;
        $lat = $z * sin($theta) + 0.006;
        return ['lng' => $lng, 'lat' => $lat];
    }

    /**
     * 根据经纬度查询出城市信息
     *
     * @param $latitude
     * @param $longitude
     * @return array
     * @throws \Exception
     */
    public static function getCityInfoByLocation($latitude, $longitude): array
    {
        $areaInfo = Search::reverseLocation($latitude . ',' . $longitude);
        $areaCityName = isset($areaInfo['city']) ? trim($areaInfo['city']) : "";
        $areaCityName = str_replace('市', '', $areaCityName);
        $areaCityInfo = self::getCityInfoByAreaName($areaCityName);
        Log::debug('根据经纬度查询城市信息', ['lat' => $latitude, 'log' => $longitude, 'city_info' => $areaCityInfo]);
        return $areaCityInfo;
    }

    /**
     * 根据areaName 查询出城市信息
     *
     * @param $areaName
     * @return array
     * @throws \Exception
     */
    public static function getCityInfoByAreaName($areaName)
    {
        $areaCityInfo = [];
        if (!$areaName) {
            return $areaCityInfo;
        }
        $areaCode = Region::getCodeByName($areaName);
        if (!$areaCode) {
            return $areaCityInfo;
        }
        $areaCityInfo['area_code'] = $areaCode;
        $areaCityInfo['area_name'] = Region::getNameByCode($areaCityInfo['area_code']);
        //todo 兼容老版本 保留下面两个字段 地区码调整完成可以删
        $areaCityInfo['city_id'] = Region::getOldCodeByCode($areaCode);
        $areaCityInfo['city_name'] = $areaName;
        return $areaCityInfo;
    }
}
